// clsFMOD.cpp: implementation of the clsFMOD class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "clsFMOD.h"

//reference count
int nFmodRefCount=0;

//fmod functions
HMODULE hmodFmod;

#define F_API __stdcall
#define FSOUND_LOOP_OFF 0x1
#define FSOUND_LOOP_NORMAL 0x2
#define FSOUND_LOADMEMORY 0x8000
#define FSOUND_FREE -1
#define FSOUND_ALL -3

typedef signed char (F_API* _FSOUND_Init)(int mixrate,int maxsoftwarechannels,unsigned int flags);
_FSOUND_Init FSOUND_Init=NULL;
typedef void (F_API* _FSOUND_Close)();
_FSOUND_Close FSOUND_Close=NULL;
typedef HANDLE (F_API* _FSOUND_Stream_Open)(const char *name_or_data,unsigned int mode,int offset,int length);
_FSOUND_Stream_Open FSOUND_Stream_Open=NULL;
typedef signed char (F_API* _FSOUND_Stream_Close)(HANDLE stream);
_FSOUND_Stream_Close FSOUND_Stream_Close=NULL;
typedef int (F_API* _FSOUND_Stream_Play)(int channel,HANDLE stream);
_FSOUND_Stream_Play FSOUND_Stream_Play=NULL;
typedef signed char (F_API* _FSOUND_Stream_SetTime)(HANDLE stream,int ms);
_FSOUND_Stream_SetTime FSOUND_Stream_SetTime=NULL;
typedef signed char (F_API* _FSOUND_Stream_Stop)(HANDLE stream);
_FSOUND_Stream_Stop FSOUND_Stream_Stop=NULL;
typedef int (F_API* _FSOUND_Stream_GetTime)(HANDLE stream);
_FSOUND_Stream_GetTime FSOUND_Stream_GetTime=NULL;
typedef int (F_API* _FSOUND_Stream_GetLengthMs)(HANDLE stream);
_FSOUND_Stream_GetLengthMs FSOUND_Stream_GetLengthMs=NULL;
typedef signed char (F_API* _FSOUND_SetPaused)(int channel,signed char paused);
_FSOUND_SetPaused FSOUND_SetPaused=NULL;
typedef signed char (F_API* _FSOUND_IsPlaying)(int channel);
_FSOUND_IsPlaying FSOUND_IsPlaying=NULL;
typedef signed char (F_API* _FSOUND_GetPaused)(int channel);
_FSOUND_GetPaused FSOUND_GetPaused=NULL;
typedef signed char (F_API* _FSOUND_SetVolume)(int channel,int vol);
_FSOUND_SetVolume FSOUND_SetVolume=NULL;
typedef HANDLE (F_API* _FMUSIC_LoadSongEx)(const char *name_or_data,int offset,int length,unsigned int mode,const int *samplelist,int samplelistnum);
_FMUSIC_LoadSongEx FMUSIC_LoadSongEx=NULL;
typedef signed char (F_API* _FMUSIC_FreeSong)(HANDLE mod);
_FMUSIC_FreeSong FMUSIC_FreeSong=NULL;
typedef signed char (F_API* _FMUSIC_SetPaused)(HANDLE mod,signed char pause);
_FMUSIC_SetPaused FMUSIC_SetPaused=NULL;
typedef signed char (F_API* _FMUSIC_PlaySong)(HANDLE mod);
_FMUSIC_PlaySong FMUSIC_PlaySong=NULL;
typedef signed char (F_API* _FMUSIC_StopSong)(HANDLE mod);
_FMUSIC_StopSong FMUSIC_StopSong=NULL;
typedef signed char (F_API* _FMUSIC_SetMasterVolume)(HANDLE mod,int volume);
_FMUSIC_SetMasterVolume FMUSIC_SetMasterVolume=NULL;
typedef signed char (F_API* _FMUSIC_IsPlaying)(HANDLE mod);
_FMUSIC_IsPlaying FMUSIC_IsPlaying=NULL;
typedef signed char (F_API* _FMUSIC_IsFinished)(HANDLE mod);
_FMUSIC_IsFinished FMUSIC_IsFinished=NULL;
typedef signed char (F_API* _FMUSIC_GetPaused)(HANDLE mod);
_FMUSIC_GetPaused FMUSIC_GetPaused=NULL;
typedef int (F_API* _FMUSIC_GetTime)(HANDLE mod);
_FMUSIC_GetTime FMUSIC_GetTime=NULL;

// Construction
clsFMOD::clsFMOD()
{
	pInit();
	v=255;
	mt=0;
	hMus=NULL;
	hStr=NULL;
	hStr2=NULL;
	lng=0;
}

// Destruction
clsFMOD::~clsFMOD()
{
	if(bRef){
		ClearUp();
		bRef=0;
		nFmodRefCount--;
		if(!nFmodRefCount) pFree();
	}
}

int clsFMOD::Init(int mixrate,int maxchannels)
{
	if(!bRef) return 0;
	return FSOUND_Init(mixrate,maxchannels,0);
}

void clsFMOD::ClearUp()
{
	if(!bRef) return;
	CloseSong();
	FSOUND_Close();
}

void clsFMOD::pInit()
{
	bRef=0;
	if(!nFmodRefCount){
		hmodFmod=LoadLibrary("fmod.dll");
		if(hmodFmod==NULL)//error!!!
			return;
		//load functions
		FSOUND_Init=(_FSOUND_Init)GetProcAddress(hmodFmod,"_FSOUND_Init@12");
		FSOUND_Close=(_FSOUND_Close)GetProcAddress(hmodFmod,"_FSOUND_Close@0");
		FSOUND_Stream_Open=(_FSOUND_Stream_Open)GetProcAddress(hmodFmod,"_FSOUND_Stream_Open@16");
		FSOUND_Stream_Close=(_FSOUND_Stream_Close)GetProcAddress(hmodFmod,"_FSOUND_Stream_Close@4");
		FSOUND_Stream_Play=(_FSOUND_Stream_Play)GetProcAddress(hmodFmod,"_FSOUND_Stream_Play@8");
		FSOUND_Stream_SetTime=(_FSOUND_Stream_SetTime)GetProcAddress(hmodFmod,"_FSOUND_Stream_SetTime@8");
		FSOUND_Stream_Stop=(_FSOUND_Stream_Stop)GetProcAddress(hmodFmod,"_FSOUND_Stream_Stop@4");
		FSOUND_Stream_GetTime=(_FSOUND_Stream_GetTime)GetProcAddress(hmodFmod,"_FSOUND_Stream_GetTime@4");
		FSOUND_Stream_GetLengthMs=(_FSOUND_Stream_GetLengthMs)GetProcAddress(hmodFmod,"_FSOUND_Stream_GetLengthMs@4");
		FSOUND_SetPaused=(_FSOUND_SetPaused)GetProcAddress(hmodFmod,"_FSOUND_SetPaused@8");
		FSOUND_IsPlaying=(_FSOUND_IsPlaying)GetProcAddress(hmodFmod,"_FSOUND_IsPlaying@4");
		FSOUND_GetPaused=(_FSOUND_GetPaused)GetProcAddress(hmodFmod,"_FSOUND_GetPaused@4");
		FSOUND_SetVolume=(_FSOUND_SetVolume)GetProcAddress(hmodFmod,"_FSOUND_SetVolume@8");
		FMUSIC_LoadSongEx=(_FMUSIC_LoadSongEx)GetProcAddress(hmodFmod,"_FMUSIC_LoadSongEx@24");
		FMUSIC_FreeSong=(_FMUSIC_FreeSong)GetProcAddress(hmodFmod,"_FMUSIC_FreeSong@4");
		FMUSIC_SetPaused=(_FMUSIC_SetPaused)GetProcAddress(hmodFmod,"_FMUSIC_SetPaused@8");
		FMUSIC_PlaySong=(_FMUSIC_PlaySong)GetProcAddress(hmodFmod,"_FMUSIC_PlaySong@4");
		FMUSIC_StopSong=(_FMUSIC_StopSong)GetProcAddress(hmodFmod,"_FMUSIC_StopSong@4");
		FMUSIC_SetMasterVolume=(_FMUSIC_SetMasterVolume)GetProcAddress(hmodFmod,"_FMUSIC_SetMasterVolume@8");
		FMUSIC_IsPlaying=(_FMUSIC_IsPlaying)GetProcAddress(hmodFmod,"_FMUSIC_IsPlaying@4");
		FMUSIC_IsFinished=(_FMUSIC_IsFinished)GetProcAddress(hmodFmod,"_FMUSIC_IsFinished@4");
		FMUSIC_GetPaused=(_FMUSIC_GetPaused)GetProcAddress(hmodFmod,"_FMUSIC_GetPaused@4");
		FMUSIC_GetTime=(_FMUSIC_GetTime)GetProcAddress(hmodFmod,"_FMUSIC_GetTime@4");
		//success?
		if(!(FSOUND_Init && FSOUND_Close && FSOUND_Stream_Open && FSOUND_Stream_Close && FSOUND_Stream_Play
			&& FSOUND_Stream_SetTime && FSOUND_Stream_Stop && FSOUND_Stream_GetTime && FSOUND_Stream_GetLengthMs && FSOUND_SetPaused
			&& FSOUND_IsPlaying && FSOUND_GetPaused && FSOUND_SetVolume && FMUSIC_LoadSongEx && FMUSIC_FreeSong
			&& FMUSIC_SetPaused && FMUSIC_PlaySong && FMUSIC_StopSong && FMUSIC_SetMasterVolume && FMUSIC_IsPlaying
			&& FMUSIC_IsFinished && FMUSIC_GetPaused && FMUSIC_GetTime)){
			pFree();
			return;
		}
	}
	bRef=1;
	nFmodRefCount++;
}

void clsFMOD::pFree()
{
	FSOUND_Init = NULL; FSOUND_Close = NULL; FSOUND_Stream_Open = NULL; FSOUND_Stream_Close = NULL; FSOUND_Stream_Play
	= NULL; FSOUND_Stream_SetTime = NULL; FSOUND_Stream_Stop = NULL; FSOUND_Stream_GetTime = NULL; FSOUND_Stream_GetLengthMs = NULL; FSOUND_SetPaused
	= NULL; FSOUND_IsPlaying = NULL; FSOUND_GetPaused = NULL; FSOUND_SetVolume = NULL; FMUSIC_LoadSongEx = NULL; FMUSIC_FreeSong
	= NULL; FMUSIC_SetPaused = NULL; FMUSIC_PlaySong = NULL; FMUSIC_StopSong = NULL; FMUSIC_SetMasterVolume = NULL; FMUSIC_IsPlaying
	= NULL; FMUSIC_IsFinished = NULL; FMUSIC_GetPaused = NULL; FMUSIC_GetTime = NULL;
	if(hmodFmod){
		FreeLibrary(hmodFmod);
		hmodFmod=NULL;
	}
}

int clsFMOD::GetMute()
{
	if(!bRef) return 0;
	return mt;
}

HANDLE clsFMOD::GetHandle()
{
	if(!bRef) return 0;
	return (hStr==NULL)?hMus:hStr;
}

int clsFMOD::OpenSong(LPCSTR FileName){
	if(!bRef) return 0;
	return OpenSong(FileName,FALSE,0,0);
}

int clsFMOD::OpenSong(LPCSTR FileName,int bLoadMemory)
{
	if(!bRef) return 0;
	return OpenSong(FileName,bLoadMemory,0,0);
}

int clsFMOD::GetLength()
{
	if(!bRef) return 0;
	return lng;
}

int clsFMOD::GetPos()
{
	if(!bRef) return 0;
	if(hMus==NULL){
		return FSOUND_Stream_GetTime(hStr);
	}else{
		//TODO:
		return 0;
	}
}

void clsFMOD::SetPos(int pos)
{
	if(!bRef) return;
	if(hMus==NULL){
		FSOUND_Stream_SetTime(hStr,pos);
	}else{
		//TODO:
		return;
	}
}

void clsFMOD::CloseSong()
{
	if(!bRef) return;
	if(hMus){
		FMUSIC_FreeSong(hMus);
		hMus = NULL;
	}
	if(hStr){
		FSOUND_Stream_Close(hStr);
		hStr = NULL;
		hStr2 = NULL;
	}
	lng = 0;
}

void clsFMOD::PauseSong()
{
	if(!bRef) return;
	if(hStr==NULL){
		FMUSIC_SetPaused(hMus,1);
	}else{
		FSOUND_SetPaused(hStr2,1);
	}
}

void clsFMOD::UnpauseSong()
{
	if(!bRef) return;
	if(hStr==NULL){
		FMUSIC_SetPaused(hMus,1);
	}else{
		FSOUND_SetPaused(hStr2,1);
	}
	pApplyVol();
}

void clsFMOD::PlaySong()
{
	if(!bRef) return;
	if(hStr==NULL){
		FMUSIC_PlaySong(hMus);
	}else if(hStr2==0){
		hStr2 = FSOUND_Stream_Play(FSOUND_FREE,hStr);
	}
	pApplyVol();
}

void clsFMOD::StopSong()
{
	if(!bRef) return;
	if(hStr==NULL){
		FMUSIC_StopSong(hMus);
	}else{
		FSOUND_Stream_Stop(hStr);
		hStr2=0;
	}
}

int clsFMOD::IsPlaying()
{
	if(!bRef) return 0;
	if(hStr==NULL)
		return FMUSIC_IsPlaying(hMus);
	if(hStr2==0) return 0;
	return FSOUND_IsPlaying(hStr2);
}

int clsFMOD::IsPaused()
{
	if(!bRef) return 0;
	if(hStr==NULL)
		return FMUSIC_GetPaused(hMus);
	if(hStr2==0) return 1;
	return FSOUND_GetPaused(hStr2);
}

int clsFMOD::IsFinished()
{
	if(!bRef) return 0;
	if(hStr==NULL)
		return FMUSIC_IsFinished(hMus);
	else
		return (FSOUND_Stream_GetTime(hStr) >= lng);
}

int clsFMOD::PlayedTime()
{
	if(!bRef) return 0;
	if(hStr==NULL)
		return FMUSIC_GetTime(hMus);
	else
		return FSOUND_Stream_GetTime(hStr);
}

int clsFMOD::GetVolume()
{
	if(!bRef) return 0;
	return v;
}

void clsFMOD::SetVolume(int vol)
{
	if(!bRef) return;
	v=vol;
	pApplyVol();
}

void clsFMOD::SetMute(int i)
{
	if(!bRef) return;
	mt=i;
	pApplyVol();
}

void clsFMOD::pApplyVol()
{
	int vol;
	if(!bRef) return;
	vol=mt?0:v;
	if(hStr==NULL)
		FMUSIC_SetMasterVolume(hMus,vol);
	else if(hStr2!=NULL)
		FSOUND_SetVolume(hStr2,vol);
}

int clsFMOD::OpenSong(LPCSTR FileName, int bLoadMemory, int offset, int length)
{
	if(!bRef) return 0;
	CloseSong();
	if(bLoadMemory) bLoadMemory=FSOUND_LOADMEMORY;
	hMus = FMUSIC_LoadSongEx(FileName,offset,length,bLoadMemory | FSOUND_LOOP_OFF,NULL,0);
	if(hMus==NULL){
		hStr = FSOUND_Stream_Open(FileName,bLoadMemory/*| FSOUND_LOOP_OFF*/,offset,length);
		if(hStr==NULL){//error!!
			lng=0;
			return 0;
		}
		lng = FSOUND_Stream_GetLengthMs(hStr);
	}else{
		lng=0;
	}
	return 1;
}
